package nancal.mp.service

import nancal.mp.db.mongo.JenkinsJobStatusEnum
import nancal.mp.db.mongo.entity.dev.JenkinsLog
import nancal.mp.db.mongo.extend.getAppDeploySetting
import nancal.mp.db.mongo.mor
import nancal.mp.service.jenkins.JenkinsService
import nancal.mp.util.JenkinsUtil
import nbcp.base.annotation.log.MyLogLevel
import nbcp.base.enums.LogLevelScopeEnum
import nbcp.base.extend.*
import nbcp.base.utils.SpringUtil
import nbcp.myoql.db.mongo.query
import nbcp.myoql.db.mongo.update
import nbcp.myoql.db.mongo.updateById
import org.slf4j.LoggerFactory
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.scheduling.annotation.Scheduled
import org.springframework.stereotype.Component
import java.time.LocalDateTime

@Component
@ConditionalOnProperty("app.scheduler", havingValue = "true", matchIfMissing = false)
class JenkinsLogTask {
    companion object {
        private val logger = LoggerFactory.getLogger(this::class.java.declaringClass)
    }


//    @Scheduled(fixedDelay = 5000)
//    @MyLogLevel(LogLevelScopeEnum.WARN)
//    fun syncSheetLog() {
//        var list = mor.dev.deploySheet.query()
//            .where { it.status mongoIn arrayOf(JenkinsJobStatusEnum.Prepare, JenkinsJobStatusEnum.Working) }
//            .where { it.createAt greaterThan LocalDateTime.now().minusHours(1) }
//            .orderByDesc { it.id }
//            .limit(0, 20)
//            .toList()
//
//        list.forEach { sheet ->
//
//            var logs = mor.dev.jenkinsLog.query()
//                .where { it.id mongoIn sheet.items.map { it.deployLog?.id } }
//                .toList();
//
//            sheet.items.forEach { deploy ->
//                var log = logs.firstOrNull { it.id == deploy.deployLog?.id }
//
//                if (log != null) {
//                    deploy.deployLog = log
//                }
//            }
//
//            var working = sheet.items.any { it.deployLog?.status == JenkinsJobStatusEnum.Working };
//            var done = sheet.items.all {
//                it.deployLog?.status == JenkinsJobStatusEnum.Success ||
//                        it.deployLog?.status == JenkinsJobStatusEnum.Failure
//            }
//
//
//            var update = mor.dev.deploySheet.updateById(sheet.id)
//                .set { it.items to sheet.items };
//
//
//            if (working) {
//                update.set { it.status to JenkinsJobStatusEnum.Working }
//            } else if (done) {
//                var hasFailure = sheet.items.any {
//                    it.deployLog?.status == JenkinsJobStatusEnum.Failure
//                }
//                if (hasFailure) {
//                    update.set { it.status to JenkinsJobStatusEnum.Failure }
//                } else {
//                    update.set { it.status to JenkinsJobStatusEnum.Success }
//                }
//            }
//
//            update.exec()
//        }
//    }

//    @Scheduled(fixedDelay = 1500)
//    @MyLogLevel(LogLevelScopeEnum.WARN)
//    fun startJenkins() {
//        var list = mor.dev.jenkinsLog.query()
//            .where { it.status mongoIn arrayOf(JenkinsJobStatusEnum.Created) }
//            .where { it.buildInfo.buildNumber greaterThan 0 }
//            .where { it.createAt greaterThan LocalDateTime.now().minusHours(1) }
//            .orderByDesc { it.id }
//            .limit(0, 20)
//            .toList();
//
//        if (list.any()) {
//            logger.Important("预处理Jenkins状态：" + list.map { it.buildInfo.serviceName }.joinToString(","))
//        }
//
//        list.forEach { log ->
//            var deploySetting = mor.dev.appDeploySetting.getAppDeploySetting(log.buildInfo.targetEnv);
//
//            var content = jenkinsService.getLogAtOnce(
//                deploySetting.jenkinsServer.jenkinsHttpUrl,
//                deploySetting.jenkinsServer.userName,
//                deploySetting.jenkinsServer.password,
//                log.buildInfo.serviceName
//            )
//
//            if (content.hasError) {
//                return@forEach
//            }
//
//            mor.dev.jenkinsLog.updateById(log.id)
//                .set { it.status to JenkinsJobStatusEnum.Prepare }
//                .exec()
//        }
//    }


    @Scheduled(fixedDelay = 1500)
    @MyLogLevel(LogLevelScopeEnum.WARN)
    fun workJenkins() {

        var list = mor.dev.jenkinsLog.query()
            .where {
                it.status mongoIn arrayOf(
                    JenkinsJobStatusEnum.Created,
                    JenkinsJobStatusEnum.Prepare,
                    JenkinsJobStatusEnum.Working
                )
            }
            .where { it.createAt greaterThan LocalDateTime.now().minusHours(24) }
            .orderByDesc { it.id }
            .limit(0, 50)
            .toList();

        var repeatTaskIds = mutableListOf<String>();
        //如果同一个任务有 Prepare,有Working ，则取消Working
        list.groupBy { it.buildInfo.serviceName }
            .forEach {
                var tasks = it.value;
                if (tasks.size > 1) {
                    //仅保留最近的一个
                    var max = tasks.maxBy { it.createAt }
                    repeatTaskIds.addAll(tasks.filter { it.id != max.id }.map { it.id })
                }
            }

        if (repeatTaskIds.size > 0) {
            mor.dev.jenkinsLog.update()
                .where { it.id mongoIn repeatTaskIds }
                .set { it.status to JenkinsJobStatusEnum.Canceled }
                .exec()

            list.removeAll { it.id.IsIn(repeatTaskIds) }
        }

        if (list.any()) {
            logger.Important(
                "处理JenkinsLogTask日志: ${
                    list.map { it.buildInfo.serviceName }.joinToString(",")
                }"
            )
        }

        list
            .forEach {
                workOne(it);
            }
    }

    private fun workOne(log: JenkinsLog) {
        var deploySetting = mor.dev.appDeploySetting.getAppDeploySetting(log.buildInfo.targetEnv);

        var content = try {
            jenkinsService.getLog(
                deploySetting.jenkinsServer.jenkinsHttpUrl,
                deploySetting.jenkinsServer.userName,
                deploySetting.jenkinsServer.password,
                log.buildInfo.serviceName,
                log.buildInfo.buildNumber
            )
        } catch (e: Exception) {
            logger.Important("配置项: ${log.buildInfo.targetEnv} ,jenkinsServer.host: ${deploySetting.jenkinsServer.jenkinsHttpUrl}")

            throw e;
        }


        if (content.value != null) {
            if (content.value == JenkinsJobStatusEnum.Expired) {
                mor.dev.jenkinsLog.updateById(log.id)
                    .set { it.status to JenkinsJobStatusEnum.Expired }
                    .exec()
                return;
            } else if (content.value == JenkinsJobStatusEnum.None) {
                mor.dev.jenkinsLog.updateById(log.id)
                    .set { it.status to JenkinsJobStatusEnum.None }
                    .exec()
                return;
            }
        }


        var jenkinsBuildNumber = content.data?.buildNumber.AsInt()

        var ret = JenkinsUtil.analyse(content.data?.content.AsString())
        if (ret.data.any() == false) return;


//        if (log.buildInfo.buildNumber > 0 && jenkinsBuildNumber > log.buildInfo.buildNumber) {
//            logger.Important("任务:${log.buildInfo.jobName} 有新的buildNumber:${jenkinsBuildNumber} !")
//            mor.dev.jenkinsLog.updateById(log.id)
//                .where { it.buildInfo.buildNumber lessThan jenkinsBuildNumber }
//                .set { it.buildInfo.buildNumber to jenkinsBuildNumber }
//                .exec();
//        }

        mor.dev.jenkinsLog.updateById(log.id)
            .set { it.stages to ret.data }
            .where { it.buildInfo.buildNumber lessThanEquals jenkinsBuildNumber }
            .apply {
                if (ret.value != null) {
                    if (ret.value.AsBoolean()) {
                        this.set { it.status to JenkinsJobStatusEnum.Success }
                    } else {
                        this.set { it.status to JenkinsJobStatusEnum.Failure }
                    }
                } else {
                    this.set { it.status to JenkinsJobStatusEnum.Working }
                }
            }
            .exec()
    }
}


val jenkinsService: JenkinsService by lazy {
    return@lazy SpringUtil.getBean();
}

